﻿@page "/credentials"
@inherits MainBase
@inject CredentialService CredentialService
@using AliasVault.RazorComponents.Tables
@using AliasVault.Client.Main.Models
@using Microsoft.Extensions.Localization

<LayoutPageTitle>Home</LayoutPageTitle>

<PageHeader
    BreadcrumbItems="@BreadcrumbItems"
    Title="@GetFilterTitle()"
    Description="@Localizer["PageDescription"]">
    <TitleActions>
        <div class="relative">
            <button @onclick="ToggleFilterDropdown" id="filterButton" class="flex items-center gap-2 text-gray-900 dark:text-white hover:text-gray-700 dark:hover:text-gray-300 focus:outline-none">
                <h1 class="flex items-baseline gap-1.5 text-xl font-semibold tracking-tight text-gray-900 dark:text-white sm:text-2xl">
                    <span>@GetFilterTitle()</span>
                    <span class="text-base text-gray-500 dark:text-gray-400">(@FilteredAndSortedCredentials.Count())</span>
                </h1>
                <svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <polyline points="6 9 12 15 18 9" />
                </svg>
            </button>

            @if (ShowFilterDropdown)
            {
                <ClickOutsideHandler OnClose="CloseFilterDropdown" ContentId="filterDropdown,filterButton">
                    <div id="filterDropdown" class="absolute left-0 top-full z-10 mt-2 w-56 origin-top-left rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-700">
                        <div class="py-1">
                            <button @onclick="() => SetFilter(CredentialFilterType.All)" class="w-full text-left px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 @(FilterType == CredentialFilterType.All ? "bg-orange-50 dark:bg-orange-900/20 text-orange-600 dark:text-orange-400" : "text-gray-700 dark:text-gray-300")">
                                @Localizer["FilterAllOption"]
                            </button>
                            <button @onclick="() => SetFilter(CredentialFilterType.Passkeys)" class="w-full text-left px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 @(FilterType == CredentialFilterType.Passkeys ? "bg-orange-50 dark:bg-orange-900/20 text-orange-600 dark:text-orange-400" : "text-gray-700 dark:text-gray-300")">
                                @Localizer["FilterPasskeysOption"]
                            </button>
                            <button @onclick="() => SetFilter(CredentialFilterType.Aliases)" class="w-full text-left px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 @(FilterType == CredentialFilterType.Aliases ? "bg-orange-50 dark:bg-orange-900/20 text-orange-600 dark:text-orange-400" : "text-gray-700 dark:text-gray-300")">
                                @Localizer["FilterAliasesOption"]
                            </button>
                            <button @onclick="() => SetFilter(CredentialFilterType.Userpass)" class="w-full text-left px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 @(FilterType == CredentialFilterType.Userpass ? "bg-orange-50 dark:bg-orange-900/20 text-orange-600 dark:text-orange-400" : "text-gray-700 dark:text-gray-300")">
                                @Localizer["FilterUserpassOption"]
                            </button>
                            <button @onclick="() => SetFilter(CredentialFilterType.Attachments)" class="w-full text-left px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 @(FilterType == CredentialFilterType.Attachments ? "bg-orange-50 dark:bg-orange-900/20 text-orange-600 dark:text-orange-400" : "text-gray-700 dark:text-gray-300")">
                                @Localizer["FilterAttachmentsOption"]
                            </button>
                        </div>
                    </div>
                </ClickOutsideHandler>
            }
        </div>
    </TitleActions>
    <CustomActions>
        <div class="relative">
            <button @onclick="ToggleSettingsDropdown" id="settingsButton" class="p-2 text-gray-500 rounded-lg hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-700">
                <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
                    <path fill-rule="evenodd" d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z" clip-rule="evenodd"></path>
                </svg>
            </button>

            @if (ShowSettingsDropdown)
            {
                <ClickOutsideHandler OnClose="CloseSettingsPopup" ContentId="settingsDropdown,settingsButton">
                    <div id="settingsDropdown" class="absolute right-0 z-10 mt-2 min-w-[220px] origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-700">
                        <div class="p-4">
                            <div class="mb-4">
                                <label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["ViewModeLabel"]</label>
                                <select @bind="ViewMode" @bind:after="CloseSettingsPopup" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
                                    <option value="grid">@Localizer["GridViewOption"]</option>
                                    <option value="table">@Localizer["TableViewOption"]</option>
                                </select>
                            </div>
                            <div class="mb-4">
                                <label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["SortOrderLabel"]</label>
                                <select @bind="SortOrder" @bind:after="CloseSettingsPopup" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
                                    <option value="@CredentialSortOrder.OldestFirst">@Localizer["OldestFirstOption"]</option>
                                    <option value="@CredentialSortOrder.NewestFirst">@Localizer["NewestFirstOption"]</option>
                                    <option value="@CredentialSortOrder.Alphabetical">@Localizer["AlphabeticalOption"]</option>
                                </select>
                            </div>
                        </div>
                    </div>
                </ClickOutsideHandler>
            }
        </div>
        <RefreshButton OnClick="LoadCredentialsAsync" ButtonText="@SharedLocalizer["Refresh"]" />
    </CustomActions>
</PageHeader>

@if (IsLoading)
{
    <LoadingIndicator />
}
else
{
    @if (DbService.Settings.CredentialsViewMode == "table")
    {
        <div class="px-4 min-h-[250px]">
            <CredentialsTable Credentials="@FilteredAndSortedCredentials.ToList()" SortOrder="@SortOrder" />
        </div>
    }
    else
    {
        <div class="grid gap-4 px-4 mb-4 md:grid-cols-4 xl:grid-cols-6">
            @if (Credentials.Count == 0)
            {
                <div class="credential-card col-span-full p-4 space-y-2 bg-amber-50 border border-primary-500 rounded-lg shadow-sm dark:border-primary-700 dark:bg-gray-800">
                    <div class="px-4 py-6 text-gray-700 dark:text-gray-200 rounded text-center flex flex-col items-center">
                        <p class="mb-2 text-lg font-semibold text-primary-700 dark:text-primary-400">@Localizer["NoCredentialsTitle"]</p>

                        <div class="max-w-md mx-auto">
                            <div class="mb-6">
                                <p class="text-sm mb-2">@Localizer["CreateFirstCredentialText"] <span class="hidden md:inline">@Localizer["NewAliasButtonText"]</span><span class="md:hidden">@Localizer["NewAliasButtonTextMobile"]</span> @Localizer["ButtonLocationText"]</p>
                            </div>

                            <div class="flex items-center my-6">
                                <div class="flex-1 h-px bg-gray-300 dark:bg-gray-600"></div>
                                <span class="px-4 text-sm text-gray-500 dark:text-gray-400">@Localizer["OrText"]</span>
                                <div class="flex-1 h-px bg-gray-300 dark:bg-gray-600"></div>
                            </div>

                            <div>
                                <p class="text-sm mb-2">@Localizer["ImportCredentialsText"]</p>
                                <a href="/settings/import-export" class="inline-block text-sm px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors dark:bg-primary-700 dark:hover:bg-primary-600">
                                    @Localizer["ImportButtonText"]
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
            }
            else if (!FilteredAndSortedCredentials.Any())
            {
                <div class="credential-card col-span-full p-4 space-y-2 bg-amber-50 border border-primary-500 rounded-lg shadow-sm dark:border-primary-700 dark:bg-gray-800">
                    <div class="px-4 py-6 text-gray-700 dark:text-gray-200 rounded text-center">
                        @if (FilterType == CredentialFilterType.Passkeys)
                        {
                            <p>@Localizer["NoPasskeysFound"]</p>
                        }
                        else if (FilterType == CredentialFilterType.Attachments)
                        {
                            <p>@Localizer["NoAttachmentsFound"]</p>
                        }
                        else
                        {
                            <p>@Localizer["NoCredentialsFound"]</p>
                        }
                    </div>
                </div>
            }
            @foreach (var credential in FilteredAndSortedCredentials)
            {
                <CredentialCard Obj="@credential"/>
            }
        </div>
    }
}

@code {
    private IStringLocalizer Localizer => LocalizerFactory.Create("Pages.Main.Credentials.Home", "AliasVault.Client");

    /// <summary>
    /// Gets or sets whether the credentials are being loaded.
    /// </summary>
    private bool IsLoading { get; set; } = true;

    /// <summary>
    /// Gets or sets the credentials.
    /// </summary>
    private List<CredentialListEntry> Credentials { get; set; } = new();

    /// <summary>
    /// Gets or sets whether the settings dropdown is shown.
    /// </summary>
    private bool ShowSettingsDropdown { get; set; }

    /// <summary>
    /// Gets or sets whether the filter dropdown is shown.
    /// </summary>
    private bool ShowFilterDropdown { get; set; }

    /// <summary>
    /// Gets or sets the filter type for the credentials.
    /// </summary>
    private CredentialFilterType FilterType { get; set; } = CredentialFilterType.All;

    /// <summary>
    /// Gets or sets the view mode for the credentials.
    /// </summary>
    private string ViewMode
    {
        get => DbService.Settings.CredentialsViewMode;
        set => DbService.Settings.SetCredentialsViewMode(value);
    }

    /// <summary>
    /// Gets or sets the sort order for the credentials.
    /// </summary>
    private CredentialSortOrder SortOrder
    {
        get => DbService.Settings.CredentialsSortOrder;
        set => DbService.Settings.SetCredentialsSortOrder(value);
    }

    /// <summary>
    /// Gets the credentials filtered and sorted according to the current filter and sort order.
    /// </summary>
    private IEnumerable<CredentialListEntry> FilteredAndSortedCredentials
    {
        get
        {
            // First apply filter
            var filtered = FilterType switch
            {
                CredentialFilterType.Passkeys => Credentials.Where(x => x.HasPasskey),
                CredentialFilterType.Aliases => Credentials.Where(x => x.HasAlias),
                CredentialFilterType.Userpass => Credentials.Where(x => x.HasUsernameOrPassword && !x.HasPasskey && !x.HasAlias),
                CredentialFilterType.Attachments => Credentials.Where(x => x.HasAttachment),
                _ => Credentials, // All
            };

            // Then apply sort
            return SortOrder switch
            {
                CredentialSortOrder.NewestFirst => filtered.OrderByDescending(x => x.CreatedAt),
                CredentialSortOrder.Alphabetical => filtered.OrderBy(x => x.Service ?? string.Empty),
                _ => filtered.OrderBy(x => x.CreatedAt), // OldestFirst (default)
            };
        }
    }

    /// <summary>
    /// Gets the title based on the active filter.
    /// </summary>
    private string GetFilterTitle()
    {
        return FilterType switch
        {
            CredentialFilterType.Passkeys => Localizer["FilterPasskeysOption"],
            CredentialFilterType.Aliases => Localizer["FilterAliasesOption"],
            CredentialFilterType.Userpass => Localizer["FilterUserpassOption"],
            CredentialFilterType.Attachments => Localizer["FilterAttachmentsOption"],
            _ => Localizer["PageTitle"],
        };
    }

    /// <summary>
    /// Toggles the settings dropdown.
    /// </summary>
    private void ToggleSettingsDropdown()
    {
        ShowSettingsDropdown = !ShowSettingsDropdown;
        StateHasChanged();
    }

    /// <summary>
    /// Toggles the filter dropdown.
    /// </summary>
    private void ToggleFilterDropdown()
    {
        ShowFilterDropdown = !ShowFilterDropdown;
        StateHasChanged();
    }

    /// <summary>
    /// Sets the filter type and closes the dropdown.
    /// </summary>
    private void SetFilter(CredentialFilterType filterType)
    {
        FilterType = filterType;
        ShowFilterDropdown = false;
        StateHasChanged();
    }

    /// <summary>
    /// Closes the filter dropdown.
    /// </summary>
    private void CloseFilterDropdown()
    {
        ShowFilterDropdown = false;
        StateHasChanged();
    }

    /// <summary>
    /// Closes the settings dropdown.
    /// </summary>
    private async Task CloseSettingsPopup()
    {
        ShowSettingsDropdown = false;

        // Reload the credentials in case the settings were changed.
        await LoadCredentialsAsync();
    }

    /// <inheritdoc />
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (firstRender)
        {
            await LoadCredentialsAsync();
        }
    }

    /// <summary>
    /// Loads and/or refreshes the credentials.
    /// </summary>
    private async Task LoadCredentialsAsync()
    {
        IsLoading = true;
        StateHasChanged();

        // Load the aliases from the webapi via AliasService.
        var credentialListEntries = await CredentialService.GetListAsync();
        if (credentialListEntries is null)
        {
            // Error loading aliases.
            GlobalNotificationService.AddErrorMessage(Localizer["FailedToLoadCredentialsMessage"], true);
            return;
        }

        if (credentialListEntries.Count == 0 && !DbService.Settings.TutorialDone)
        {
            // Redirect to the welcome page.
            NavigationManager.NavigateTo("/welcome");
            return;
        }

        // Pass unsorted list to the view - sorting will be handled by the table/grid components
        Credentials = credentialListEntries;
        IsLoading = false;
        StateHasChanged();
    }
}
